package post

import (
	"context"
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
	"time"

	"mall/common/globalkey"
	"mall/common/jwt"
	"mall/common/mqueuex"
	"mall/common/utils/pointy"
	"mall/service/attachment/rpc/attachmentclient"
	"mall/service/backend/api/internal/svc"
	"mall/service/backend/api/internal/types"
	"mall/service/backend/common/enum/errorcode"
	"mall/service/backend/common/errorx"
	"mall/service/forum/rpc/forumclient"
	"mall/service/setting/rpc/settingclient"
	"mall/service/user/rpc/userclient"

	"github.com/zeromicro/go-zero/core/logx"
)

type UpdatePostLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewUpdatePostLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdatePostLogic {
	return &UpdatePostLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *UpdatePostLogic) UpdatePost(req *types.UpdateForumPostReq) (*types.BaseMsgResp, error) {
	// logx.Infof("UpdateForumPostReq : %+v ", req)

	if len(req.Ids) > 0 {
		res, err := l.svcCtx.ForumRpc.BackendUpdatePost(l.ctx, &forumclient.ForumPostInfo{
			Status: req.Status,
			Ids:    req.Ids,
		})
		if err != nil {
			return nil, err
		}

		if req.Status != nil && int32(*req.Status) == globalkey.StatusApproved && res.IdUserIdMap != nil {
			l.distributeIntegral(req.Ids, res.IdUserIdMap)
		}

		return &types.BaseMsgResp{
			Success: true,
			Msg:     l.svcCtx.Trans.Trans(l.ctx, res.Msg),
		}, nil
	}

	if req.Id == nil || *req.Id == 0 {
		return nil, errorx.NewCodeError(errorcode.InvalidArgument,
			l.svcCtx.Trans.Trans(l.ctx, "common.validationError"))
	}

	if req.Title != nil && len(strings.TrimSpace(*req.Title)) == 0 {
		return nil, errorx.NewCodeError(errorcode.InvalidArgument,
			l.svcCtx.Trans.Trans(l.ctx, "forum.postTitleRequired"))
	}

	if req.AuthorId != nil && *req.AuthorId == 0 {
		return nil, errorx.NewCodeError(errorcode.InvalidArgument,
			l.svcCtx.Trans.Trans(l.ctx, "forum.postAuthorRequired"))
	}

	var skipMeta bool
	if req.SkipMeta != nil && *req.SkipMeta > 0 {
		skipMeta = true
	}
	var skipMedia bool
	if req.SkipMedia != nil && *req.SkipMedia > 0 {
		skipMedia = true
	}
	var skipCard bool
	if req.SkipCard != nil && *req.SkipCard > 0 {
		skipCard = true
	}
	var skipContent bool
	if req.SkipContent != nil && *req.SkipContent > 0 {
		skipContent = true
	}

	var content *string
	var contentFiltered *string
	if !skipContent && req.Content != nil && len(strings.TrimSpace(*req.Content)) > 0 {
		parts := strings.Split(strings.TrimSpace(*req.Content), globalkey.EditorSplitSymbol)
		if len(parts) > 0 {
			content = pointy.GetPointer(parts[0])
		}
		if len(parts) > 1 {
			contentFiltered = pointy.GetPointer(parts[1])
		}
	}

	var meta []*forumclient.MetaInfo
	if !skipMeta && len(req.Meta) > 0 {
		for _, v := range req.Meta {
			meta = append(meta, &forumclient.MetaInfo{
				Id:    v.Id,
				Key:   v.Key,
				Value: v.Value,
			})
		}
	}

	var allCard []*forumclient.PostCardInfo
	var newCard []*forumclient.PostCardInfo
	if !skipCard {
		if len(req.AllCard) > 0 {
			for _, v := range req.AllCard {
				allCard = append(allCard, &forumclient.PostCardInfo{
					LinkUrl: v.LinkUrl,
					Title:   v.Title,
				})
			}
		}

		if len(req.NewCard) > 0 {
			for _, v := range req.NewCard {
				newCard = append(newCard, &forumclient.PostCardInfo{
					Id:       v.Id,
					Type:     v.Type,
					LinkUrl:  v.LinkUrl,
					Title:    v.Title,
					PicUrl:   v.PicUrl,
					Subtitle: v.Subtitle,
					Label:    v.Label,
					Price:    v.Price,
				})
			}
		}
	}

	var allMedia []*forumclient.MediaInfo
	newThumbMap := make(map[string]*types.MediaInfo)
	newMediaMap := make(map[string]*types.MediaInfo)
	var newMediaIds []string // 用于查询 attachmentRpc
	var thumbnail = pointy.GetPointer(uint32(1))
	var newMedia []*forumclient.MediaInfo
	var newAttachmentIds []string // 用于主动通知 attachmentRpc
	if !skipMedia {
		if len(req.AllMedia) > 0 { // 富文本所有图片
			for _, v := range req.AllMedia {
				allMedia = append(allMedia, &forumclient.MediaInfo{
					Id:  v.Id,
					Url: v.Url,
				})
			}
		}

		if len(req.NewThumb) > 0 { // 封面图新图片
			for _, v := range req.NewThumb {
				if v.Id != nil && len(*v.Id) > 0 {
					if _, ok := newThumbMap[*v.Id]; !ok { // 忽略重复id
						newThumbMap[*v.Id] = v
						newMediaIds = append(newMediaIds, *v.Id)
					}
				} else {
					newMedia = append(newMedia, &forumclient.MediaInfo{
						Uid:       v.Uid,
						Thumbnail: thumbnail,
						Order:     v.Order,
						Url:       v.Url,
						Name:      v.Name,
						MimeType:  v.MimeType,
						AltText:   v.AltText,
						MetaData:  v.MetaData,
					})
				}
			}
		}

		if len(req.NewMedia) > 0 { // 富文本新图片
			for _, v := range req.NewMedia {
				if v.Id != nil && len(*v.Id) > 0 {
					if _, ok := newMediaMap[*v.Id]; !ok { // 忽略重复id
						newMediaMap[*v.Id] = v
						newMediaIds = append(newMediaIds, *v.Id)
					}
				} else {
					newMedia = append(newMedia, &forumclient.MediaInfo{
						Uid:      v.Uid,
						Order:    v.Order,
						Url:      v.Url,
						Name:     v.Name,
						MimeType: v.MimeType,
						AltText:  v.AltText,
						MetaData: v.MetaData,
					})
				}
			}
		}
	}

	if len(newMediaIds) > 0 {
		res, err := l.svcCtx.AttachmentRpc.BackendGetFileList(l.ctx, &attachmentclient.FileListReq{
			Ids: pointy.GetPointer(strings.Join(newMediaIds, ",")),
		})
		if err != nil {
			return nil, err
		}

		if len(res.List) > 0 {
			for _, v := range res.List {
				if v.Id != nil && len(*v.Id) > 0 {
					mediaId := *v.Id
					var url string
					if v.Url != nil && len(*v.Url) > 0 {
						url = fmt.Sprintf("%s%s", l.svcCtx.Config.NfsConf.StaticUrl, *v.Url)
					}
					if len(url) == 0 && v.Path != nil && len(*v.Path) > 0 {
						url = fmt.Sprintf("%s%s", l.svcCtx.Config.NfsConf.ProxyUrl, *v.Path)
					}

					if media, ok := newThumbMap[mediaId]; ok {
						newMedia = append(newMedia, &forumclient.MediaInfo{
							Uid:       media.Uid,
							Id:        v.Id,
							Thumbnail: thumbnail,
							Order:     media.Order,
							Uri:       media.Url,
							Url:       pointy.GetPointer(url),
							Name:      media.Name,
							MimeType:  media.MimeType,
							AltText:   media.AltText,
							MetaData:  media.MetaData,
						})
						newAttachmentIds = append(newAttachmentIds, mediaId)
						continue
					}

					if media, ok := newMediaMap[mediaId]; ok {
						newMedia = append(newMedia, &forumclient.MediaInfo{
							Uid:      media.Uid,
							Id:       v.Id,
							Order:    media.Order,
							Uri:      media.Url,
							Url:      pointy.GetPointer(url),
							Name:     media.Name,
							MimeType: media.MimeType,
							AltText:  media.AltText,
							MetaData: media.MetaData,
						})
						newAttachmentIds = append(newAttachmentIds, mediaId)
					}
				}
			}
		}
	}

	createdBy := pointy.GetPointer(jwt.GetBackendUserId(l.ctx))

	res, err := l.svcCtx.ForumRpc.BackendUpdatePost(l.ctx, &forumclient.ForumPostInfo{
		Id:                  req.Id,
		PostTitle:           req.Title,
		PostContent:         content,
		PostContentFiltered: contentFiltered,
		PostExcerpt:         req.Excerpt,
		AuthorId:            req.AuthorId,
		Status:              req.Status,
		CommentStatus:       req.CommentStatus,
		Sort:                req.Sort,
		TagIds:              req.TagIds,
		CreatedBy:           createdBy,
		Meta:                meta,
		AllCard:             allCard,
		NewCard:             newCard,
		AllMedia:            allMedia,
		NewMedia:            newMedia,
		SkipMedia:           req.SkipMedia,
		SkipMeta:            req.SkipMeta,
		SkipCard:            req.SkipCard,
		SkipTag:             req.SkipTag,
		SkipContent:         req.SkipContent,
	})
	if err != nil {
		return nil, err
	}

	if len(newAttachmentIds) > 0 {
		_, err = l.svcCtx.AttachmentRpc.CreateFileLog(l.ctx, &attachmentclient.CreateFileLogReq{
			FileIds:    newAttachmentIds,
			Put:        pointy.GetPointer(uint32(1)),
			Thumbnail:  pointy.GetPointer(uint32(1)),
			ObjectId:   req.Id,
			ObjectType: pointy.GetPointer(uint32(globalkey.AttachmentLogTypeForumPost)),
		})
		if err != nil {
			logx.Errorw("UpdatePost CreateFileLog err", logx.Field("detail", err.Error()))
		}
	}

	return &types.BaseMsgResp{
		Success: true,
		Msg:     l.svcCtx.Trans.Trans(l.ctx, res.Msg),
	}, nil
}

func (l *UpdatePostLogic) distributeIntegral(ids []uint64, idUserIdMap map[uint64]uint64) error {
	//查询任务频率
	task, err := l.svcCtx.SettingRpc.BackendGetIntegralTaskById(l.ctx, &settingclient.UUIDReq{
		Id: mqueuex.UserTaskForumReview,
	})
	if err != nil {
		logx.Errorw("UpdatePost distributeIntegral SettingRpc.BackendGetIntegralTaskById err", logx.Field("detail", err.Error()))
		return err
	}

	if task.Id == nil || *task.Id == 0 {
		return nil
	}

	tid := *task.Id

	if task.Frequency != nil && *task.Frequency > 0 {
		//有上限
		//查询用户当天该任务是否超出次数
		now := time.Now()
		// 获取当天的起始时间（午夜）
		startOfDay := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
		// 获取当天的终止时间（午夜前的最后一秒）
		endOfDay := startOfDay.AddDate(0, 0, 1).Add(-time.Second)
		for _, id := range ids {
			if uid, ok := idUserIdMap[id]; ok {
				var filters []string
				filters = append(filters, "UserId,equalTo:"+strconv.FormatUint(uid, 10))
				filters = append(filters, "TaskId,equalTo:"+strconv.FormatUint(tid, 10))
				filters = append(filters, "Status,equalTo:"+strconv.FormatInt(int64(globalkey.StatusEnabled), 10))
				filters = append(filters, "CreatedAt,moreThanOrEqualTo:"+startOfDay.Format("2006-01-02 15:04:05"))
				filters = append(filters, "CreatedAt,lessThan:"+endOfDay.Format("2006-01-02 15:04:05"))
				userTaskLog, err := l.svcCtx.UserRpc.GetIntegralTaskLogList(l.ctx, &userclient.BaseListReq{
					Filter: pointy.GetPointer(strings.Join(filters, ";")),
				})
				if err != nil {
					logx.Errorw("UpdatePost distributeIntegral UserRpc.GetIntegralTaskLogList err", logx.Field("detail", err.Error()))
				} else {
					//userTaskLog.Total < uint64(*task.Frequency)  已完成次数 < 每日限制次数
					if userTaskLog != nil && userTaskLog.Total < uint64(*task.Frequency) {
						l.doDistributeIntegral(tid, uid, id)
					}
				}
			}
		}
	} else {
		for _, id := range ids {
			if uid, ok := idUserIdMap[id]; ok {
				l.doDistributeIntegral(tid, uid, id)
			}
		}
	}

	return nil
}

func (l *UpdatePostLogic) doDistributeIntegral(tid uint64, uid uint64, pid uint64) error {
	m := mqueuex.DistributePointsMessage{
		UserId:     pointy.GetPointer(uid),
		TaskId:     pointy.GetPointer(tid),
		SourceId:   pointy.GetPointer(pid),
		SourceType: pointy.GetPointer(globalkey.UserAssetSourceTypeTask),
	}
	body, err := json.Marshal(m)
	if err != nil {
		logx.Errorw(fmt.Sprintf("UpdatePost distributeIntegral doDistributeIntegral json.Marshal error: %+v", err))
		return fmt.Errorf("UpdatePost distributeIntegral doDistributeIntegral json.Marshal error: %+v", err)
	}

	err = l.svcCtx.KqDistributePointsClient.Push(string(body))
	if err != nil {
		logx.Errorw(fmt.Sprintf("UpdatePost distributeIntegral doDistributeIntegral KqDistributePointsClient error: %+v", err))
		return fmt.Errorf("UpdatePost distributeIntegral doDistributeIntegral KqDistributePointsClient error:%+v", err)
	}

	return nil
}
